#pragma once
#include <windows.h>
#include <string>
#include <type_traits>
#include <stdexcept>
#include <memory>
#include <functional>
#include <mutex>

namespace CppWinApi::Windows
{
    /**
     * @enum ESharedMemoryScope
     * @brief 定义共享内存的作用范围
     * @value Local 本地会话共享内存（仅当前用户会话可见）
     * @value Global 全局共享内存（所有用户会话可见）
     */
    enum class ESharedMemoryScope
    {
        Local,
        Global
    };

    /**
     * @class SharedMemory
     * @brief 共享内存封装类，提供跨进程共享数据的能力
     * @tparam UUID 唯一标识符字符串，用于生成唯一的共享对象名称
     * @tparam TSharedData 共享的数据类型，必须是平凡类型(trivial type)
     * @tparam SCOPE 共享内存范围（默认Local）
     *
     * @note 该类使用Windows API实现共享内存功能，包含线程安全和异常处理机制
     * @warning 共享数据类型必须是平凡类型(trivial type)，否则会导致未定义行为
     */
    template <const char *UUID,
              typename TSharedData,
              ESharedMemoryScope SCOPE = ESharedMemoryScope::Local,
              typename = std::enable_if_t<std::is_class_v<TSharedData> && std::is_default_constructible_v<TSharedData>>>
    class SharedMemory
    {
        static_assert(!std::is_polymorphic_v<TSharedData>,
                      "TSharedData must not be polymorphic");
        static_assert(std::is_standard_layout_v<TSharedData>,
                      "TSharedData must be standard layout");
        static_assert(alignof(TSharedData) <= __alignof(max_align_t),
                      "Alignment requirement too strict");

        // 静态断言确保共享数据类型是平凡的
        static_assert(std::is_trivial_v<TSharedData>,
                      "TSharedData must be a trivial type for shared memory usage");

    public:
        /**
         * @typedef ActionHandle
         * @brief 用于操作共享数据的回调函数类型
         */
        using ActionHandle = std::function<void(TSharedData *)>;

        static SharedMemory<UUID, TSharedData, SCOPE> &GetInstance()
        {
            static SharedMemory<UUID, TSharedData, SCOPE> gInstance;
            return gInstance;
        }

    private:
        HANDLE mHandle = nullptr;           ///< 文件映射对象的句柄
        HANDLE mMutexHandle = nullptr;      ///< 互斥量句柄，用于同步访问
        TSharedData *mSharedData = nullptr; ///< 映射到进程地址空间的共享内存指针
        const std::string mClassId;         ///< 类唯一标识符，用于生成共享对象名称
        mutable std::mutex mOperationMutex; ///< 用于保护内部操作的互斥锁

        /**
         * @brief 生成唯一的共享对象名称
         * @param baseName 基础名称
         * @return 完整的唯一名称字符串
         *
         * @details 根据SCOPE模板参数决定使用"Global\\"或"Local\\"前缀，
         *          结合UUID和mClassId生成全局唯一的名称
         */
        std::string MakeUniqueName(const std::string &baseName) const
        {
            const char *scopePrefix = (SCOPE == ESharedMemoryScope::Global) ? "Global\\" : "Local\\";
            return scopePrefix + std::string(UUID) + "_" + mClassId + "_" + baseName;
        }

        /**
         * @brief 初始化共享内存和互斥量
         * @throws std::runtime_error 如果任何一步操作失败
         *
         * @details 执行以下操作序列：
         * 1. 创建/打开互斥量
         * 2. 创建/打开共享内存
         * 3. 映射共享内存视图
         */
        void Initialize()
        {
            const auto memoryName = MakeUniqueName("shared_memory");
            const auto mutexName = MakeUniqueName("shared_memory_mutex");

            // 1. 创建或打开互斥量
            mMutexHandle = CreateMutexA(nullptr, FALSE, mutexName.c_str());
            if (!mMutexHandle)
            {
                throw std::runtime_error("CreateMutex failed: " + std::to_string(GetLastError()));
            }

            // 2. 创建或打开共享内存
            mHandle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, memoryName.c_str());
            if (!mHandle)
            {
                DWORD error = GetLastError();
                if (error != ERROR_FILE_NOT_FOUND)
                {
                    CloseHandle(mMutexHandle);
                    throw std::runtime_error("OpenFileMapping failed: " + std::to_string(error));
                }

                // 共享内存不存在，创建新的
                mHandle = CreateFileMappingA(
                    INVALID_HANDLE_VALUE, // 使用物理内存
                    nullptr,              // 默认安全属性
                    PAGE_READWRITE,       // 可读可写权限
                    0,                    // 高位文件大小
                    sizeof(TSharedData),  // 低位文件大小
                    memoryName.c_str());  // 共享内存名称

                if (!mHandle)
                {
                    CloseHandle(mMutexHandle);
                    throw std::runtime_error("CreateFileMapping failed: " + std::to_string(GetLastError()));
                }
            }

            // 3. 映射视图到进程地址空间
            mSharedData = static_cast<TSharedData *>(MapViewOfFile(
                mHandle,               // 文件映射对象句柄
                FILE_MAP_ALL_ACCESS,   // 读写权限
                0, 0,                  // 偏移量
                sizeof(TSharedData))); // 映射大小

            if (!mSharedData)
            {
                DWORD err = GetLastError();
                CloseHandle(mMutexHandle);
                CloseHandle(mHandle);
                throw std::runtime_error("MapViewOfFile failed: " + std::to_string(err));
            }
        }

    public:
        /**
         * @brief 构造函数
         * @details 初始化类唯一标识符并调用Initialize()方法
         */
        SharedMemory() : mClassId("7256ef32-f549-4bdf-8a41-920f009c4f01")
        {
            Initialize();
        }

        /**
         * @brief 析构函数
         * @details 释放所有资源，包括：
         * 1. 取消内存映射
         * 2. 关闭互斥量句柄
         * 3. 关闭文件映射对象句柄
         */
        ~SharedMemory()
        {
            std::lock_guard<std::mutex> lock(mOperationMutex);
            if (mSharedData)
            {
                UnmapViewOfFile(mSharedData);
                mSharedData = nullptr;
            }
            if (mMutexHandle)
            {
                CloseHandle(mMutexHandle);
                mMutexHandle = nullptr;
            }
            if (mHandle)
            {
                CloseHandle(mHandle);
                mHandle = nullptr;
            }
        }

        // 禁止拷贝和移动
        SharedMemory(const SharedMemory &) = delete;
        SharedMemory &operator=(const SharedMemory &) = delete;
        SharedMemory(SharedMemory &&) = delete;
        SharedMemory &operator=(SharedMemory &&) = delete;

        /**
         * @brief 获取共享数据指针
         * @return TSharedData* 共享数据指针
         * @note 调用此方法会获取内部互斥锁，确保线程安全
         */
        TSharedData *Get() const
        {
            std::lock_guard<std::mutex> lock(mOperationMutex);
            return mSharedData;
        }

        class MutexHandleGuard
        {
        public:
            explicit MutexHandleGuard(HANDLE hMutex) : mHandle(hMutex)
            {
                WaitForSingleObject(mHandle, INFINITE); // 构造时加锁
            }
            ~MutexHandleGuard()
            {
                ReleaseMutex(mHandle); // 析构时自动解锁
            }
            MutexHandleGuard(const MutexHandleGuard &) = delete;
            MutexHandleGuard &operator=(const MutexHandleGuard &) = delete;

        private:
            HANDLE mHandle;
        };

        /**
         * @brief 安全执行共享内存操作（支持返回值）
         * @tparam TResult 返回值类型（允许 void）
         * @param action 操作共享数据的回调函数，接受 TSharedData* 参数
         * @return 非 void 类型时返回 action 的执行结果
         * @throws std::bad_function_call 当 action 为空时抛出
         * @throws 可能传播 action 中抛出的异常
         *
         * @details 执行流程：
         * 1. 获取内部线程锁 (mOperationMutex)
         * 2. 获取跨进程互斥量所有权 (mMutexHandle)
         * 3. 执行用户回调 action
         * 4. 自动释放所有锁（RAII 机制保证）
         *
         * @note 线程安全：通过双重锁机制保证线程/进程安全
         * @warning 回调函数执行时间应尽量短，避免长时间阻塞其他进程
         */
        template <
            typename TLambdaFunc,
            typename... TArgs,
            typename TResult = decltype(std::declval<TLambdaFunc>()(std::declval<TSharedData *>(), std::declval<TArgs>()...)),
            // TLambdaFunc 约束，必须是 class(lambda 就是一个匿名类)，lambda 参数必须是 TSharedData *，返回值类型必须是 TResult
            typename = std::enable_if_t<std::is_class_v<TLambdaFunc> && std::is_invocable_r_v<TResult, TLambdaFunc, TSharedData *, TArgs...>>>
        TResult Action(TLambdaFunc &&lambda, TArgs... args)
        {
            //  && std::is_same_v<, TResult>
            // 第一重锁：保护类内部状态（进程内线程安全）
            std::lock_guard<std::mutex> lock(mOperationMutex);

            // 第二重锁：保护共享内存数据（跨进程安全）
            // RAII 封装确保即使 action 抛出异常也能释放互斥量
            MutexHandleGuard winLock(mMutexHandle);

            // 编译时分支：根据返回值类型选择执行方式
            if constexpr (std::is_void_v<TResult>)
            {
                // void 特化：无返回值
                std::forward<TLambdaFunc>(lambda)(mSharedData, std::forward<TArgs>(args)...);
                // 注意：此处不需要 return 语句
            }
            else
            {
                // 非 void 类型：转发返回值
                return std::forward<TLambdaFunc>(lambda)(mSharedData, std::forward<TArgs>(args)...);
                // 编译器会确保所有路径都有返回值（否则报错）
            }

            // 注：非 void 分支必须通过 return 返回，此处不会执行
        }

        /**
         * @brief 检查共享内存是否有效
         * @return bool 是否有效
         * @retval true 所有句柄和指针都有效
         * @retval false 任一资源无效
         */
        bool IsValid() const
        {
            std::lock_guard<std::mutex> lock(mOperationMutex);
            return mHandle != nullptr && mMutexHandle != nullptr && mSharedData != nullptr;
        }
    };
}